#include "bdpp/parser.h"

bool bd::parse_int32(const char* str, int32_t* value) {
  char* end = nullptr;
  const long long_value = strtol(str, &end, 10);  // NOLINT

  // Has strtol() consumed all characters in the string?
  if (*end != '\0') {
    return false;
  }

  // Is the parsed value in the range of an Int32?
  const auto result = static_cast<int32_t>(long_value);
  if (long_value == std::numeric_limits<long>::max() || long_value == std::numeric_limits<long>::min() ||
      // The parsed value overflows as a long.  (strtol() returns
      // LONG_MAX or LONG_MIN when the input overflows.)
      result != long_value
      // The parsed value overflows as an Int32.
  ) {
    return false;
  }

  *value = result;
  return true;
}

bool bd::parse_double(const char* str, double* value) {
  char* end = nullptr;
  const double double_value = strtod(str, &end);  // NOLINT

  // Has strtol() consumed all characters in the string?
  if (*end != '\0') {
    // No - an invalid character was encountered.
    return false;
  }

  *value = double_value;
  return true;
}

bool bd::check_truthy(const std::string& str) {
  if (str.size() == 1) {
    char v = str[0];
    return isalnum(v) && !(v == '0' || v == 'f' || v == 'F' || v == 'n' || v == 'N');
  } else if (!str.empty()) {
    std::string value_lower(str);
    std::transform(value_lower.begin(), value_lower.end(), value_lower.begin(), [](char c) { return static_cast<char>(::tolower(c)); });
    return !(value_lower == "false" || value_lower == "no" || value_lower == "off");
  } else
    return true;
}